package simpledb.common;

import simpledb.storage.Field;
import simpledb.storage.IntField;
import simpledb.storage.StringField;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;

/**
 * 表示 SimpleDB 中数据类型的类
 * 类型是静态对象，由该类定义，因此 Type 的构造函数是私有的
 */
public enum Type implements Serializable {

    /**
     * 整数类型 INT_TYPE
     * 占用 4 字节
     */
    INT_TYPE() {
        @Override
        public int getLen() {
            return 4; // 整数占 4 个字节
        }

        @Override
        public Field parse(DataInputStream dis) throws ParseException {
            try {
                // 从输入流读取一个整数并创建对应的 Field 对象 --- IntField 对象
                return new IntField(dis.readInt());
            } catch (IOException e) {
                throw new ParseException("无法解析整数", 0);
            }
        }
    },

    /**
     * 字符串类型 STRING_TYPE
     * 每个字符串最多 STRING_LEN 个字符（128），加上存储长度的 4 个字节
     */
    STRING_TYPE() {
        @Override
        public int getLen() {
            return STRING_LEN + 4; // 4 字节用于存储字符串长度，剩下的用于存储字符串的内容
        }

        @Override
        public Field parse(DataInputStream dis) throws ParseException {
            try {
                int strLen = dis.readInt(); // 读取字符串的长度
                byte[] bs = new byte[strLen];
                dis.read(bs); // 读取实际字符串的字节内容
                dis.skipBytes(STRING_LEN - strLen); // 跳过剩余空间（因为字符串定长为 128）

                // 将字节数组转换为字符串，并创建 StringField 对象
                return new StringField(new String(bs), STRING_LEN);
            } catch (IOException e) {
                throw new ParseException("无法解析字符串", 0);
            }
        }
    };

    // 所有字符串的最大长度为 128 个字符
    public static final int STRING_LEN = 128;

    /**
     * 获取该类型的一个字段所需要的字节数
     * @return 字段占用的字节数
     */
    public abstract int getLen();

    /**
     * 从指定的 DataInputStream 中读取数据，并解析为相应的 Field 对象
     * @param dis               输入流
     * @return                  解析后的 Field 对象
     * @throws ParseException   如果数据格式不正确或读取出错
     */
    public abstract Field parse(DataInputStream dis) throws ParseException;
}
